作者

中国科学院计算技术研究所

摘要

虽然研究表明敏捷芯片设计方法有望以更有效的方式维持计算性能的扩展,但由于两个主要障碍,它在实际应用中的使用仍然有限:1)缺乏工具链和开发框架支持敏捷芯片设计,特别是大规模现代处理器。 2)传统的验证方法敏捷性较差,成为整个流程的主要瓶颈。为了解决这两个问题,我们提出了 MINJIE,一个支持敏捷处理器开发流程的开源平台。 Minjie集成了一套逻辑设计,功能验证,性能建模,塞利康前验证和调试的广泛工具,以提高最先进的处理器设计的开发效率。
我们通过使用敏捷方法来构建两代开源超级级别的RISC-V处理器代码为Xiangshan的开源超级量表,以证明Minjie的使用和有效性。我们使用Spec CPU2006基准测试了Xiangshan的性能,并证明了Xiangshan实现了行业竞争性的绩效。

本文的意义

敏捷芯片设计方法可能减少芯片开发成本和设计周期。
但是存在两个问题,首先是目前尚不清楚这种方式是否适合应用于现代处理器等大规模设计,其次是在大规模的芯片设计中,验证是一个主要的瓶颈,然而这种设计方式主要关注快速原型设计而非验证。
为了解决这两个问题,提出了MINJIE平台,其中包含丰富的敏捷开发工具以及基于Diff-Rule的敏捷验证机制,并通过这套平台在十个月内设计了第一代香山处理器。

MINJIE解决哪些问题

处理器功能验证——协同仿真环境中的不确定性问题

处理器验证的常见做法是构建一个联合仿真框架来比较待测设计 (DUT) 和参考模型 (REF) 的结果之间的等效性。结果可以配置根据验证目标具有不同的内容。例如,为了确保 ISA 级合规性,结果被定义为处理器的体系结构状态,例如通用寄存器和程序计数器。然而,这种严格的等效性测试策略必须解决受设计的微架构实现细节影响的非确定性行为问题,例如,不精确的异常和异步中断可能会不可预测地破坏处理器的正常指令流。对于没有微架构信息的参考模型,存在更多的非确定性场景,这些事件通常会导致 DUT 和 REF 的结果出现分歧。这也是形式验证和软件测试中广泛接受的挑战,需要维护和探索大量的状态空间,本文演示了如何解决协同仿真环境中的不确定性问题。

验证框架——敏捷设计过程中的不匹配问题

在传统的验证方式是给定相同的设计规范,RTL工程师用Verilog构建处理器,而验证工程师则用其他语言(例如SystemVerilog、C/C++)为处理器的各个部分和级别开发相应的参考模型。 Verilog 设计 (DUT) 和 REF 被放入 UVM 等验证框架中,以检查其结果之间的等效性。
然而敏捷设计涉及频繁生成更新设计实例的高级HDL,这种新的设计范式给参考模型及与DUT的交互带来两个挑战。首先REF需要涵盖REF不同迭代中不同微架构的相关细节,并避免其结果之间的不匹配。其次,高层 HDL 的微小修改可能会导致 Verilog 的重大变化,并严重破坏原始验证代码。因此,验证工程师深受敏捷开发之苦,本文解决了这两个问题。

RTL设计的仿真与Debug——软件RTL模拟器的效率问题

硬件设计需要长时间的RTL仿真来完成验证过程,常见方法包括基于软件、FPGA 和仿真器的 RTL 仿真。FPGA运行速度最快,很多工作已经解决了可扩展性、可调试性和长综合时间的问题,但仍需针对大规模设计进行改进。Cadence Palladium、Mentor Veloce 和 Synopsys Zebu等仿真器可以以 MHz 的速度仿真大型电路,具有完全可视性和良好的可调试性,但他们非常昂贵,学术界和工业界都难以大规模部署。
基于软件的 RTL 模拟器是最常用的工具,可提供模拟电路的完整可见性。然而,对于大规模设计,软件方法的运行速度为 KHz,当启用必要的调试信息(例如波形和日志)时,软件方法会变得更慢。解决基于软件的 RTL 仿真器的调试效率具有重要意义,因为它们几乎用于所有硬件项目。本文演示了加快调试过程的方法。

性能评估

准确的投片前性能评估和验证对于高性能处理器非常重要。使用敏捷方法评估处理器设计也至关重要,因为它会影响功能探索的效率。本文演示了基于软件RTL仿真的性能评估工作流程。

MINJIE平台的详细介绍——如何解决上述问题

高效处理器验证方法

论文创新性地提出了基于规则(Diff-Rule)完成对设计行为非确定性的刻画,有效降低参考模型与验证框架的开发与维护成本,提高硬件验证效率。论文进一步发现并明确了 RISC-V 处理器与典型多层 Cache 结构中的非确定性行为来源,实现了针对通用 RISC-V 处理器的协同仿真验证框架 DiffTest,已成功地应用于香山、一生一芯等项目的开发过程中。

LightSSS

软件 RTL 仿真是硬件验证与调试的常用手段,出错时的错误现场复现则是调试时最耗时的一步,该步骤需要获取额外的调试信息,无论信息的格式如何,调试模式下的 RTL 仿真通常比正常模式下慢得多。以香山为例,当启用波形时,RTL仿真速度下降至8.5%,而导出文本日志也会导致仿真速度下降55%
如下图所示,lightSSS的原理是采用进程抽象的方式,用fork函数对仿真进程进行快照,具体过程如下:

讲稿

我要介绍的这篇文章是计算所的一篇文章——Towards Developing High Performance RISC-V Processors Using Agile Methodology(使用敏捷方法开发高性能RISC-V处理器),大家都知道香山处理器的开发使用的不是Verilog HDL而是Chisel在介绍这篇文章的内容之前,需要先简单介绍一下Chisel。

对于每一个数字电路工程师来说,Verilog HDL是再熟悉不过的了,然而Verilog HDL是C语言时代的产物,其开发效率低下的问题越来越明显。芯片研发每年动辄需要上亿研发费用,投入上百研发人员,还需要企业承担流片失败的巨大风险。

Chisel也是一种硬件设计语言,解决了Verilog HDL的很多痛点,其中最重要的是在硬件电路设计中引入了面向对象的特性。工程师能够编写Chisel代码来描述硬件电路,生成可综合的Verilog HDL代码,从而大大提升开发效率。

有关Chisel对开发效率的提升可以看一下香山文档中的这个案例:一位专业的工程师和一位做过CPU课程设计拥有9个月Chisel开发经验的本科生,处理一个相同的任务——实现一个接入RISC-V处理器的L2Cache,工程师使用传统的Verilog开发方法,本科生使用Chisel进行开发。最后工程师花费了六周,写了约1700行的有效代码,最后效果不如本科生三天写出的约350行代码。

结论是:Chisel开发效率远高于Verilog;实现相同的功能,Chisel代码量仅为Verilog的1/5(因此香山的5万行Chisel代码相当于25万行Verilog代码);Chisel的开发质量不比Verilog差。

那么问题来了,那既然Chisel看上去这么优秀,为什么还没取代Verilog和VHDL? 敏捷开发方法可能减少芯片开发成本和设计周期,同时保持合理的PPA规范。但是存在两个问题,首先是目前尚不清楚这种方式是否适合应用于现代处理器等大规模设计,虽然已经有不少使用敏捷设计方法设计的芯片,但大多都是研究原型,规模较小或不太复杂,缺乏具有敏捷开发工具的高质量硬件项目,敏捷和开放的方法论对于高性能和复杂的设计仍然没有得到认可。其次是在大规模的芯片设计中,验证是一个主要的瓶颈,然而这种设计方式主要关注快速原型设计而非验证,因此需要更多工具来支持这种开发方式。

为了解决这两个问题,这篇文章提出了MINJIE平台,其中包含丰富的敏捷开发工具以及基于Diff-Rule的敏捷验证机制,并通过这套平台在十个月内设计了第一代香山处理器。

这张图是香山的文档里找来的,浮在水面上的是香山处理器,水下的是MINJIE平台,也正是这篇文章的重点。

首先要介绍MINJIE平台的第一个组件,指令级在线差分验证框架DiffTEST。 处理器验证的常见做法是构建一个联合仿真框架来比较待测设计 (DUT) 和参考模型 (REF) 的结果之间的等效性。如图a所示给定相同的设计规范,RTL工程师用Verilog构建处理器,而验证工程师则用其他语言(例如SystemVerilog、C/C++)为处理器的各个部分和级别开发相应的参考模型。Verilog设计 (DUT) 和REF被放入UVM等验证框架中,以检查其结果之间的等效性。

但是对于敏捷开发方式来说,这种方法不是很可行,修改高层HDL时可能会导致生成的Verilog代码出现重大变化,如图b所示,随着Chisel代码设计的迭代,会不断生成不同的Verilog代码。可能有的同学没有见过Chisel生产的Verilog代码,他大概是长这样的,语法是可综合的Verilog语法,但是看上去和我们平时写的Verilog有很大的差别,使本就不好读的Verilog代码雪上加霜,而验证工程师既希望REF能够涵盖DUT中的细节,又要在设计的一次次迭代中维持REF和DUT之前的一一对应关系,非常困难。

理想情况是图c这种,Chisel生成多次Verilog代码,都只需要一组验证逻辑和验证代码。

针对这个问题,本文提出基于差分规则的敏捷测试方法(Diff-Rule based Agile Verification),核心思想是对于根据同一规范的两种实现, 给定相同定义的输入, 它们的行为应当一致。

那么两种实现,其中一种已经是我们的CPU了,另一种就选一个简单的,模拟器就可以了。

顺着这个思路,DiffTest的模型就是这个样子,基本原理就是CPU执行一条指令,模拟器也执行一条指令,由于遵循相同的设计规范,指令执行完毕后两者的状态也应该是对齐的,然后对比逻辑比较两者状态,选择报错或者继续。

除此之外,还要解决一些别的问题,实际上,模拟器无法仅靠自己在一些行为上正确地与处理器对齐, 无法仅依靠模拟器直接验证处理器的行为。例如MMIO在RISC-V架构中会表现为特定地址区域的load/store指令,但是模拟器没法模拟外部设备的行为,导致REF无法判断DUT是否正确,除了MMIO,这种行为还有很多,例如与微结构相关的Store Page Fault的判断,与一致性相关的多核的情况等等。这些问题导致REF无法判断什么是“正确“的结果,无法确认DUT的正确性。

本文认为上述问题的原因主要是模拟器缺乏足够的信息,所以解决方案就是通过某种方法向模拟器传递微结构状态、中断信息、MMIO结果以同步模拟器与处理器。

这个方法就是使用 Probe 完成微结构信息的传递。

信息探针在设计阶段插入到处理器设计中,受Chisel等高层次HDL支持,作为设计中的一段逻辑,负责在 RTL 仿真期间提取所需信息。

在传统的被广泛接受的通用验证方法中(例如UVM),提取验证所需信息的逻辑是由验证工程师手动编写的,他们在了解验证需求后找出感兴趣的信号。

然而,在敏捷开发方法下,硬件设计可能会随着大量的内部信号定义而频繁变化,导致验证工程师重复且无意义的移植工作。相反的是,探针是由了解实现细节并承担推进设计责任的设计人员编写的。

Probe是沟通设计与验证之间的桥梁,DiffTest = diff-rules + probes。

然后是MINJIE平台的第二个组件,一种轻量级仿真快照技术LightSSS。

调试时,如果如图a这样,始终工作在debug模式下,那么由于调试需要波形和日志等信息,这些信息会降低仿真速度,无论信息的格式如何,调试模式下的RTL仿真通常比正常模式下慢得多。以香山为例,在Debug Mode下RTL仿真速度下降至8.5%,而导出文本日志也会导致仿真速度下降55%。

这里举一个直观的例子使用Verilator仿真效率≈10K指令/s;运行coremark 1轮循环 – 0.45分钟;启动最小linux – 6.20分钟;启动debian至登录提示符 – 9.67天。

为了解决这个问题,本文提出lightSSS,其原理是采用进程抽象的方式,用fork函数对仿真进程进行快照。如图b所示主仿真进程每隔一定时间fork一个子进程,子进程自我阻塞等待父进程的信号,这样每个子进程保存了父进程在特定时间的仿真状态。父进程仿真发生错误时,通知最新的子进程开始运行并打印波形或者debug信息,父进程等待子进程结束后退出。简单来说就是跑两个进程,一个先跑一个后跑,先跑的进程先遇到bug,然后通知后跑的进程你即将遇到bug,进入调试模式。通过这种方法避免了仿真程序长时间运行在Debug模式下,从而提升效率。

另一个问题是拍摄快照带来的仿真速度降低,快照通常是通过以包含所有所需信息的文件映像的形式、连接电路状态和其他必要的仿真信息来创建的。然而,频繁转储快照会导致严重的性能下降,最先进的 RTL 模拟快照工具 LiveSim 报告称性能下降了 10% 到 20%。为了解决快照效率问题,本文发现DUT内存的大部分内容在两次快照之间保持不变。因此,我们可以只记录两个RTL模拟快照之间的差异状态,而不是存储整个快照。

那么两者结合,就形成了图d这样的状态,两个进程同时运行,每隔一段时间拍摄一次快照,如果先运行的进程遇到bug了,通知后运行的进行恢复到最近的一次快照,然后进入debug模式。

这种方法带来了显著的效率提升,和Verilator提供的--savable机制相比;Verilator编译效率达到3.80倍;g++编译效率达到2.83倍;10轮coremark运行效率达到1.17倍;单次快照效率达到6951.40倍。

然后是MINJIE平台的第三个组件,效率接近QEMU的高性能解释器NEMU。我们知道投片前性能评估对于高性能处理器非常重要,为了实现准确、敏捷的性能评估方法,MINJIE 首先提供了一个名为 NEMU(New EMUlator)的高性能指令集解释器,它对不同的检测和分析任务表现出高度的灵活性。DiffTest中REF采用的模拟器就是NEMU。

NEMU是一个解释型模拟器,为了实现高性能,NEMU采用了大量的优化技术。1.对于同一条指令,并不是每次执行都需要取指、译码、计算新PC,NEMU使用cache把译码结果缓存起来,缓存命中时指令可以直接执行。2.借助主机(x86)的浮点指令和库函数,大幅提升浮点指令模拟执行时的性能,Spike文中提到是最先进的RISC-V模拟器,他在模拟浮点指令时,调用的库中的代码,而NEMU直接调用x86的指令。 3.译码时,将0号寄存器的写入重定向到无用变量,当指令被执行时,无需再判断是否为0号寄存器。4.为伪指令和压缩指令实现专门的执行函数,减少执行时的步骤,由于这里的伪指令是普通指令的特殊情况,它可以少一些步骤,因此QUME单独为伪指令和特殊指令做了特殊处理,从而减少了执行时的步骤。实际上除了文中提到的这些优化,NEMU还做了许多别的优化,最后的效果直观的来看就是这样,例如模拟一条add指令,Spike需要做这些操作,而NEMU通过各种优化少做了很多操作。

这样直接带来的就是效率的提升,将NEMU与Spike、QEMU-TCI和Dromajo进行比较。其中,Spike是最先进的RISC-V解释器,QEMU-TCI是QEMU的解释器模式,Dromajo是BOOM 的参考模型。在Spike、QEMU-TCI和Dromajo中,Spike表现最好。对于 SPECint 2006,Spike 平均可以达到 142 MIPS(每秒百万条指令)。同时,NEMU最终平均可以达到733 MIPS,大约是Spike的5.16倍。对于 SPECfp 2006,Spike运行速度更慢,仅达到106MIPS。这是因为Spike通过调用SoftFloat来解释浮点指令。通过采用主机浮点指令,NEMU可以在浮点基准测试中实现 817 MIPS,约为 Spike 的7.71倍,对于某些基准测试(410.bwaves)甚至达到16倍。

为了证明MINJIE的有效性,本文用它构建了一个名为香山的高性能RISC-V处理器,这个各位计算所的同学应该比我熟悉,我就简单讲一下。

香山是一款超标量乱序六发射结构RISC-V 处理器,支持 RV64GCBK ISA。香山处理器前端流水线包括分支预测单元、取指单元、指令缓冲等单元,顺序取指。后端包括译码、重命名、重定序缓冲、保留站、整型/浮点寄存器堆、整型/浮点运算单元。香山将访存子系统分离开,包括两条 load 流水线,两条 store addr 流水线,两条 store data 流水线,以及独立的 load 队列和 store 队列,store buffer 等。缓存包括 ICache、DCache、L2/L3 Cache (HuanCun)、TLB 和预取器等模块。

作为敏捷开发的第一步,香山是使用Chisel HDL实现的,总代码行~63K。值得注意的是,大多数设计参数都是可根据给定的时序、面积和预算(例如缓存大小)约束进行配置的,YQH和NH两代微架构对应的频率为 1.3GHz 和 2GHz 。

香山处理器采用SPEC CPU2006基准测试套件的性能评估结果。它使用 -O2 优化标志进行编译,YQH的ISA为RV64GC,NH的ISA为RV64GCB。我们使用广泛接受的SPEC/GHz指标进行定量评估,该指标与IPC成正比。

YQH芯片的性能评估结果如图所示(YQH-ASIC-DDR4-1600)表明,香山在1GHz下在SPECint 2006上达到了7.03,在SPECfp 2006上达到了7.00。

通过设计香山这样一个相对结构复杂并且高性能的处理器,展示了MINJIE平台的能力,并表明它们可以作为敏捷硬件开发和高性能处理器研究的架构创新平台。